/*
 * @Author: zhang zhijiang 2824735304@qq.com
 * @Date: 2025-04-27 16:37:40
 * @LastEditors: zhang zhijiang 2824735304@qq.com
 * @LastEditTime: 2025-05-16 18:50:32
 * @FilePath: /linux/http/httpser.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#pragma once
#include "log.hpp"
#include "sock.hpp"
#include <iostream>
#include <cstring>
#include <vector>
#include <sstream>
#include <fstream>
using namespace std;
static uint16_t defaultport = 8080;
static string sep = "\r\n";
static string wwwroot = "./wwwroot";
class httpserver;
class threaddata
{
public:
    threaddata(int sockfd, httpserver *s) : sockfd_(sockfd), svr(s)
    {
    }

public:
    int sockfd_;
    httpserver *svr;
};
class httprequest
{
public:
    void deserial(string content)
    {
        while (true)
        {
            size_t pos = content.find(sep);
            if (pos == std::string::npos)
                break; // 找不到sep退出
            std::string temp = content.substr(0, pos);
            if (temp.empty())
                break; // 找到了空行退出
            request_header.push_back(temp);
            content.erase(0, pos + sep.size()); // 每次找到后加
        }
        text = content;
    }
    void debugprint()
    {
        for (auto s : request_header)
        {
            cout << s << endl;
        }
        cout << "method:" << method << endl;
        cout << "file_path:" << file_path << endl;
        cout << "http_version:" << http_version << endl;
        cout<<"suffix:"<<suffix<<endl;
    }
    void parse()
    {
        stringstream ss(request_header[0]);
        ss >> method >> file_path >> http_version;
        int pos = file_path.rfind(".");
        if (pos != string::npos)
        {
            suffix = file_path.substr(pos); // 从点开始截取
        }
        else
        {
            suffix = ".html";
        }
        string path = wwwroot;
        if (file_path == "/" || file_path == "/index.html")
            path += "/index.html";
        else
            path += file_path;
        file_path = path;
    }

public:
    vector<string> request_header;
    string text;
    string method;
    string file_path;
    string http_version;
    string suffix;
};
class httpserver
{
public:
    httpserver(uint16_t port = defaultport) : _port(port)
    {
        desc[".html"] = "text/html";
        desc[".png"] = "image/png";
    }
    ~httpserver()
    {
    }

    bool start()
    {
        _listensock.Init();
        _listensock.Bind(_port);
        _listensock.Listen();
        for (;;)
        {
            std::string clientip;
            uint16_t clientport;

            int sockfd = _listensock.Accept(clientip, clientport);
            threaddata td(sockfd, this);
            pthread_t pid;
            pthread_create(&pid, nullptr, http, &td);
        }
    }
    static std::string ReadHtmlContent(const string &path,string suffix) // 从html文件中读取
    {
       
        std::string content;
        if (suffix == ".html")
        {
            std::ifstream in(path);
            if (!in.is_open())
                return "";
            string line;
            while (getline(in, line))
            {
                content += line;
            }
            in.close();
        }
        else
        {
            std::ifstream in(path, std::ios::binary);
            if (!in.is_open())
                return "";
            in.seekg(0, std::ios_base::end);
            auto len = in.tellg();
            in.seekg(0, std::ios_base::beg);
            content.resize(len);
            in.read((char *)content.c_str(), content.size());
            in.close();
        }

        return content;
    }
    string suffix_to_desc(string suffix)
    {

        string content;
        auto pos = desc.find(suffix);
        if (desc.find(suffix) == desc.end())
        {
            content = desc[".html"];
        }
        else
        {
            content = desc[suffix];
        }
        return content;
    }
    void handlerhttp(int sockfd)
    {
        char buffer[12800];
        int n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
        if (n > 0)
        {
            buffer[n] = 0;
            // // cout << buffer << endl;
            httprequest ht;
            ht.deserial(buffer);
            ht.parse();
            ht.debugprint();
            string content = ReadHtmlContent(ht.file_path,ht.suffix);
            // cout<<content<<endl;
            string response_line;
            if (content.empty())
            {
                string err;
                err = wwwroot;
                err += "/error.html";
                content = ReadHtmlContent(err,ht.suffix);
                response_line = "HTTP/1.0 404 NOT FOUND\r\n";
            }
            else
            {
                response_line = "HTTP/1.0 200 OK\r\n";
            }
            string len = "Content-Length: ";
            len += to_string(content.size());
            len += sep;

            string type = "Content-Type: ";
            type += suffix_to_desc(ht.suffix);
            type += sep;
            string response = response_line;
            response += len;
            response += type;
            response += sep;
            response += content;
            
            send(sockfd, response.c_str(), response.size(), 0);
        }
        close(sockfd);
    }
    static void *http(void *args)
    {
        pthread_detach(pthread_self());
        threaddata *td = static_cast<threaddata *>(args);
        td->svr->handlerhttp(td->sockfd_);
        return nullptr;
    }

private:
    uint16_t _port;
    sock _listensock;
    unordered_map<string, string> desc;
};